home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / src / dcpp / cexp.c < prev    next >
C/C++ Source or Header  |  1997-09-09  |  13KB  |  702 lines

  1. /*
  2.  *    (c)Copyright 1992-1997 Obvious Implementations Corp.  Redistribution and
  3.  *    use is allowed under the terms of the DICE-LICENSE FILE,
  4.  *    DICE-LICENSE.TXT.
  5.  */
  6.  
  7. /*
  8.  *  CEXP.C
  9.  *
  10.  */
  11.  
  12. #include "defs.h"
  13.  
  14. Prototype long ParseIfExp(char *, short *, long, short);
  15. Prototype void PushOp(short, short, short);
  16. Prototype int TopOfOpStack(void);
  17. Prototype int SecondOffOpStack(void);
  18. Prototype void PushAtom(long, short);
  19.  
  20. Local int CombineOp(void);
  21. Local int GetAtomStack(short *, long *);
  22. Local int ParseCharConst(char *, long, long, long *);
  23. Local int ParseInt(char *, long, long, long *);
  24. Local int HexDig(char);
  25. Local int OctDig(char);
  26.  
  27. #define MAXATOM     128
  28. #define MAXOPER     128
  29.  
  30. #define CGTEQ    256
  31. #define CGTGT    257
  32. #define CLTEQ    258
  33. #define CLTLT    259
  34. #define CNOTEQ    260
  35. #define CEQEQ    261
  36. #define CSYM    262
  37. #define CUMI    263
  38.  
  39. #define CDEFINED    264
  40. #define CANDAND     265
  41. #define COROR        266
  42.  
  43. #define QBIN    4        /*    binary operator, else unary */
  44. #define LR    1        /*    left to right, else        */
  45. #define RL    2        /*    right to left            */
  46. #define BLR    (LR|QBIN)
  47. #define BRL    (RL|QBIN)
  48. #define XX    0
  49.  
  50. typedef struct Atom {
  51.     long    Value;
  52.     short   Undef;
  53.     short   Reserved;
  54. } Atom;
  55.  
  56. typedef struct Oper {
  57.     short   Token;
  58.     short   Pri;
  59.     short   Type;
  60.     short   Reserved;
  61. } Oper;
  62.  
  63. static Atom AtomStack[MAXATOM];
  64. static Oper OperStack[MAXOPER];
  65. static short AtomIdx;
  66. static short OperIdx;
  67. static short BaseAtomIdx;
  68. static short BaseOperIdx;
  69.  
  70. long
  71. ParseIfExp(char *buf, short *pundef, long max, short subsym)
  72. {
  73.     short unary = 1;
  74.     short i = 0;
  75.     short parens = 0;
  76.     short baseOperIdx;
  77.     short baseAtomIdx;
  78.  
  79.     baseOperIdx = BaseOperIdx = OperIdx;
  80.     baseAtomIdx = BaseAtomIdx = AtomIdx;
  81.  
  82.     while (i < max) {
  83.     short c = buf[i];
  84.  
  85.     ++i;
  86.     if (c == ' ' || c == 9 || c == '\n')
  87.         continue;
  88.  
  89.     if (unary) {    /*  int, sym, !exp, ~exp (exp)    */
  90.         switch(c) {
  91.         case '!':
  92.         case '~':
  93.         PushOp(c, 140, RL);
  94.         break;
  95.         case '-':
  96.         PushOp(CUMI, 140, RL);
  97.         break;
  98.         case '(':
  99.         ++parens;
  100.         PushOp(c, 0, XX);
  101.         break;
  102.         default:
  103.         if (c >= '0' && c <= '9') {
  104.             long v;
  105.             /*
  106.             printf("%d(%c) ", i - 1, buf[i-1]);
  107.             */
  108.             i = ParseInt(buf, i - 1, max, &v);
  109.             /*
  110.             printf("%d INT %d\n", i, v);
  111.             */
  112.             PushAtom(v, 0);
  113.             unary = 0;
  114.  
  115.             break;
  116.         }
  117.         /*
  118.          *  NOTE, handles 'defined' by pushing unary op instead
  119.          *      of atom.
  120.          */
  121.         if (SymbolChar[c]) {    /*  SymbolChar[] includes '0'-'9'   */
  122.             short ni;
  123.  
  124.             --i;
  125.             ni = ExtSymbol(buf, i, max);
  126.             if (ni - i == 7 && strncmp(buf + i, "defined", 7) == 0) {
  127.             PushOp(CDEFINED, 140, RL);
  128.             } else if (TopOfOpStack() == CDEFINED || SecondOffOpStack() == CDEFINED) {
  129.             Sym *sym = FindSymbol(buf + i, ni - i);
  130.             if (sym)
  131.                 PushAtom(1, 0);
  132.             else
  133.                 PushAtom(0, 1);
  134.             unary = 0;
  135.             } else {
  136.             Sym *sym = FindSymbol(buf + i, ni - i);
  137.  
  138.             if (sym) {
  139.                 short xundef;
  140.                 long v;
  141.                 if (subsym == 0) {
  142.                 v = 0;
  143.                 xundef = 0;
  144.                 } else {
  145.                     /* We need to actually parse the symbol and then  */
  146.                     /* evaluate any arguments.  This code closely     */
  147.                     /* mimics the code found in HandleSymbol, but it  */
  148.                     /* has the additional requirement of not actually */
  149.                     /* sending anything out to the output file.       */
  150.                 short oldType = sym->Type;
  151.                 short creType = 0;
  152.  
  153.                 {
  154.                     long it = ni;
  155.                     /* The -max is so that we can flag to the */
  156.                     /* routine to not output anything         */
  157.                     if (PrepareSymbolArgs(sym, buf, &it, -max) == NULL)
  158.                     goto syntax;
  159.                     ni = it;
  160.                 }
  161.                 /*
  162.                  * If pushing a macro argument for replace we must
  163.                  * enable the macro it came from.  This allows
  164.                  * MAX(MAX(1,2),3) while disallowing loop conditions,
  165.                  * i.e.    #define BAR(x)  BAR(1,x)
  166.                 */
  167.  
  168.                 if (sym->Type & SF_MACROARG) {
  169.                     if (sym->Creator == NULL)
  170.                     cerror(EFATAL_SOFTWARE_ERROR_CREATOR);
  171.                     creType = sym->Creator->Type;
  172.                     sym->Creator->Type &= ~SF_RECURSE;
  173.                 }
  174.  
  175.                 v = ParseIfExp(sym->Text, &xundef, sym->TextLen, 1);
  176.  
  177.                 if (sym->Type & SF_MACROARG)
  178.                     sym->Creator->Type = creType;
  179.  
  180.                 if (sym->NumArgs >= 0)
  181.                 {    /*  undef symbol args symbols        */
  182.                     short j;
  183.                     for (j = 0; j < sym->NumArgs; ++j)
  184.                     {
  185.                     if (UndefSymbol(sym->Args[j], sym->ArgsLen[j]) == 0)
  186.                         cerror(EFATAL_SOFTWARE_ERROR_MACRO,
  187.                                sym->SymName, sym->Args[j]);
  188.                     }
  189.                 }
  190.                 sym->Type = oldType;
  191.  
  192.                 BaseOperIdx = baseOperIdx;
  193.                 BaseAtomIdx = baseAtomIdx;
  194.                 }
  195.                 PushAtom(v, xundef);
  196.             } else {
  197.                 PushAtom(0, 1);
  198.             }
  199.             unary = 0;
  200.             }
  201.             i = ni;
  202.             break;
  203.         }
  204.         if (c == '\'') {
  205.             long v;
  206.             i = ParseCharConst(buf, i - 1, max, &v);
  207.             PushAtom(v, 0);
  208.             unary = 0;
  209.             break;
  210.         }
  211. syntax:
  212.         cerror(EERROR_SYNTAX_ERROR);
  213. syntax2:
  214.         *pundef = 1;
  215.         AtomIdx = baseAtomIdx;
  216.         OperIdx = baseOperIdx;
  217.         return(0);
  218.         }
  219.     } else {    /*  + - * / % & | ^ <= << < == != > >> >=   */
  220.         unary = 1;
  221.  
  222.         switch(c) {
  223.         case '+':
  224.         case '-':
  225.         PushOp(c, 120, BLR);
  226.         break;
  227.         case '*':
  228.         case '/':
  229.         case '%':
  230.         PushOp(c, 130, BLR);
  231.         break;
  232.         case '&':
  233.         if (i < max && buf[i] == '&') {
  234.             PushOp(CANDAND, 50, BLR);
  235.             ++i;
  236.         } else {
  237.             PushOp(c, 60, BLR);
  238.         }
  239.         break;
  240.         case '^':
  241.         PushOp(c, 70, BLR);
  242.         break;
  243.         case '|':
  244.         if (i < max && buf[i] == '|') {
  245.             ++i;
  246.             PushOp(COROR, 40, BLR);
  247.         } else {
  248.             PushOp(c, 80, BLR);
  249.         }
  250.         break;
  251.         case '<':
  252.         if (i < max) {
  253.             short d = buf[i];
  254.             if (d == '<') {
  255.             PushOp(CLTLT, 110, BLR);
  256.             ++i;
  257.             break;
  258.             }
  259.             if (d == '=') {
  260.             PushOp(CLTEQ, 100, BLR);
  261.             ++i;
  262.             break;
  263.             }
  264.         }
  265.         PushOp(c, 100, BLR);
  266.         break;
  267.         case '=':
  268.         if (i >= max || buf[i] != '=')
  269.             goto syntax;
  270.         PushOp(CEQEQ, 90, BLR);
  271.         ++i;
  272.         break;
  273.         case '!':
  274.         if (i >= max || buf[i] != '=')
  275.             goto syntax;
  276.         PushOp(CNOTEQ, 90, BLR);
  277.         ++i;
  278.         break;
  279.         case '>':
  280.         if (i < max) {
  281.             short d = buf[i];
  282.             if (d == '>') {
  283.             PushOp(CGTGT, 110, BLR);
  284.             ++i;
  285.             break;
  286.             }
  287.             if (d == '=') {
  288.             PushOp(CGTEQ, 100, BLR);
  289.             ++i;
  290.             break;
  291.             }
  292.         }
  293.         PushOp(c, 100, BLR);
  294.         break;
  295.         case ')':
  296.         unary = 0;
  297.         if (parens == 0) {
  298.             cerror(EERROR_TOO_MANY_CLOSE_PARENS);
  299.             goto syntax2;
  300.         }
  301.         --parens;
  302.         while ((c = TopOfOpStack()) && c != '(')
  303.             CombineOp();
  304.         if (c == 0)
  305.             goto syntax;
  306.         CombineOp();
  307.         break;
  308.         default:
  309.         goto syntax;
  310.         }
  311.     }
  312.     }
  313.     while (TopOfOpStack() >= 0 && CombineOp() >= 0);
  314.  
  315.     if (TopOfOpStack() >= 0)
  316.     goto syntax;
  317.  
  318.     {
  319.     long v;
  320.  
  321.     if (GetAtomStack(pundef, &v) < 0)
  322.         goto syntax;
  323.     if (GetAtomStack(NULL, NULL) >= 0)  /*    shouldn't be anything left */
  324.         goto syntax;
  325.     AtomIdx = baseAtomIdx;
  326.     OperIdx = baseOperIdx;
  327.     dbprintf(("RESULT %ld %d\n", v, *pundef));
  328.     return(v);
  329.     }
  330. }
  331.  
  332. void
  333. PushOp(short token, short pri, short type)
  334. {
  335.     if (pri) {
  336.     while (OperIdx > BaseOperIdx) {
  337.         Oper *op = OperStack + OperIdx - 1;
  338.         if (pri > op->Pri)
  339.         break;
  340.         if (pri == op->Pri && (type & RL))
  341.         break;
  342.         if (CombineOp() < 0) {
  343.         cerror(EERROR_SYNTAX_ERROR);
  344.         break;
  345.         }
  346.     }
  347.     }
  348.     if (OperIdx == MAXOPER) {
  349.     cerror(EERROR_EXPRESSION_TOO_COMPLEX);
  350.     return;
  351.     }
  352.     {
  353.     Oper *op = OperStack + OperIdx++;
  354.  
  355.     op->Pri = pri;
  356.     op->Token = token;
  357.     op->Type = type;
  358.     }
  359. }
  360.  
  361. int
  362. TopOfOpStack()
  363. {
  364.     if (OperIdx <= BaseOperIdx)
  365.     return(-1);
  366.     return((int)OperStack[OperIdx-1].Token);
  367. }
  368.  
  369. int
  370. SecondOffOpStack()
  371. {
  372.     if (OperIdx - 1 <= BaseOperIdx)
  373.     return(-1);
  374.     return((int)OperStack[OperIdx-2].Token);
  375. }
  376.  
  377.  
  378. void
  379. PushAtom(long val, short isundef)
  380. {
  381.     Atom *atom;
  382.  
  383.     if (AtomIdx == MAXATOM) {
  384.     cerror(EERROR_EXPRESSION_TOO_COMPLEX);
  385.     return;
  386.     }
  387.     atom = AtomStack + AtomIdx++;
  388.     atom->Value = val;
  389.     atom->Undef = isundef;
  390. }
  391.  
  392. int
  393. CombineOp()
  394. {
  395.     Oper *op;
  396.     Atom *a1, *a2;
  397.     Atom ar;
  398.  
  399.     if (OperIdx <= BaseOperIdx)
  400.     return(-1);
  401.     op = OperStack + --OperIdx;
  402.  
  403.     if (AtomIdx <= BaseAtomIdx)
  404.     return(-1);
  405.     a1 = AtomStack + --AtomIdx;
  406.  
  407.     if (op->Type & QBIN) {
  408.     if (AtomIdx <= BaseAtomIdx)
  409.         return(-1);
  410.     a2 = AtomStack + --AtomIdx;
  411.     }
  412.  
  413.     if (op->Type & QBIN) {
  414.     ar.Undef = a1->Undef | a2->Undef;
  415.  
  416.     switch(op->Token) {
  417.     case '+':
  418.         ar.Value = a2->Value + a1->Value;
  419.         break;
  420.     case '-':
  421.         ar.Value = a2->Value - a1->Value;
  422.         break;
  423.     case '*':
  424.         ar.Value = a2->Value * a1->Value;
  425.         break;
  426.     case '/':
  427.         if (a1->Value)
  428.         ar.Value = a2->Value / a1->Value;
  429.         else
  430.         ar.Undef = 1;
  431.         break;
  432.     case '%':
  433.         if (a1->Value)
  434.         ar.Value = a2->Value % a1->Value;
  435.         else
  436.         ar.Undef = 1;
  437.         break;
  438.     case '&':
  439.         ar.Value = a2->Value & a1->Value;
  440.         break;
  441.     case '|':
  442.         ar.Value = a2->Value | a1->Value;
  443.         break;
  444.     case '^':
  445.         ar.Value = a2->Value ^ a1->Value;
  446.         break;
  447.     case '<':
  448.         ar.Value = a2->Value < a1->Value;
  449.         break;
  450.     case CLTLT:
  451.         ar.Value = a2->Value << a1->Value;
  452.         break;
  453.     case CLTEQ:
  454.         ar.Value = a2->Value <= a1->Value;
  455.         break;
  456.     case CEQEQ:
  457.         ar.Value = a2->Value == a1->Value;
  458.         break;
  459.     case CNOTEQ:
  460.         ar.Value = a2->Value != a1->Value;
  461.         break;
  462.     case '>':
  463.         ar.Value = a2->Value > a1->Value;
  464.         break;
  465.     case CGTGT:
  466.         ar.Value = a2->Value >> a1->Value;
  467.         break;
  468.     case CGTEQ:
  469.         ar.Value = a2->Value >= a1->Value;
  470.         break;
  471.     case CANDAND:
  472.         if (a2->Value && a1->Value)
  473.         ar.Value = 1;
  474.         else
  475.         ar.Value = 0;
  476.         break;
  477.     case COROR:
  478.         if (a2->Undef == 0 && a2->Value) {
  479.         ar.Value = 1;
  480.         ar.Undef = 0;
  481.         } else if (a1->Undef == 0 && a1->Value) {
  482.         ar.Value = 1;
  483.         ar.Undef = 0;
  484.         } else {
  485.         ar.Value = 0;
  486.         }
  487.         break;
  488.     default:
  489.         cerror(EFATAL_ERROR_PARSING_EXP);
  490.         break;
  491.     }
  492.     } else {
  493.     ar.Undef = a1->Undef;
  494.  
  495.     switch(op->Token) {
  496.     case '!':
  497.         ar.Value = !a1->Value;
  498.         break;
  499.     case '~':
  500.         ar.Value = ~a1->Value;
  501.         break;
  502.     case CUMI:
  503.         ar.Value = -a1->Value;
  504.         break;
  505.     case '(':
  506.         ar.Value = a1->Value;
  507.         break;
  508.     case CDEFINED:
  509.         ar.Undef = 0;
  510.         if (a1->Undef)
  511.         ar.Value = 0;
  512.         else
  513.         ar.Value = 1;
  514.         break;
  515.     default:
  516.         cerror(EFATAL_ERROR_PARSING_EXP);
  517.         break;
  518.     }
  519.     }
  520.     AtomStack[AtomIdx++] = ar;
  521.     dbprintf(("op %c %03x result %ld (%d)\n", op->Token, op->Token, ar.Value, ar.Undef));
  522.     return(0);
  523. }
  524.  
  525. int
  526. GetAtomStack(pundef, pv)
  527. short *pundef;
  528. long *pv;
  529. {
  530.     Atom *at;
  531.  
  532.     if (AtomIdx <= BaseAtomIdx) {
  533.     if (pundef)
  534.         *pundef = 1;
  535.     return(-1);
  536.     }
  537.     at = AtomStack + --AtomIdx;
  538.     if (pundef)
  539.     *pundef = at->Undef;
  540.     if (pv)
  541.     *pv = at->Value;
  542.     return(0);
  543. }
  544.  
  545. int
  546. ParseCharConst(buf, i, max, pv)
  547. char *buf;
  548. long i;
  549. long max;
  550. long *pv;
  551. {
  552.     ubyte c;
  553.     long v = 0;
  554.  
  555.     if (buf[i] != '\'')
  556.     return(0);
  557.     ++i;
  558.     while (i < max && (c = buf[i]) != '\'') {
  559.     ++i;
  560.     if (c == '\\' && i < max) {
  561.         c = buf[i++];
  562.         switch(c) {
  563.         case 'a':
  564.         c = 7;
  565.         break;
  566.         case 'b':
  567.         c = 8;
  568.         break;
  569.         case 'f':
  570.         c = 'f'&0x1F;
  571.         break;
  572.         case 'n':
  573.         c = 10;
  574.         break;
  575.         case 'r':
  576.         c = 13;
  577.         break;
  578.         case 't':
  579.         c = 9;
  580.         break;
  581.         case 'v':
  582.         c = 11;
  583.         break;
  584.         case 'x':
  585.         {
  586.             short n;
  587.             short r = 0;
  588.             short cnt = 2;
  589.  
  590.             while (cnt && (n = HexDig(c)) > 0) {
  591.             r = (r << 4) + n;
  592.             c = buf[i++];
  593.             --cnt;
  594.             }
  595.             if (cnt)
  596.             --i;
  597.             c = r;
  598.         }
  599.         break;
  600.         case '0':
  601.         case '1':
  602.         case '2':
  603.         case '3':
  604.         case '4':
  605.         case '5':
  606.         case '6':
  607.         case '7':
  608.         case '8':
  609.         case '9':
  610.         {
  611.             short cnt;
  612.             short r;
  613.             short n;
  614.  
  615.             for (r = cnt = 0; cnt < 3 && (n = OctDig(c)) >= 0; ++cnt) {
  616.             r = (r << 3) + n;
  617.             c = buf[i++];
  618.             }
  619.             --i;
  620.             c = r;
  621.         }
  622.         break;
  623.         default:
  624.         c = buf[i];
  625.         break;
  626.         }
  627.     }
  628.     v = (v << 8) | c;
  629.     }
  630.     *pv = v;
  631.     if (i < max)    /*    skip closing single quote   */
  632.     ++i;
  633.     else
  634.     cerror(EERROR_UNTERMINATED_CHARCONST);
  635.     return(i);
  636. }
  637.  
  638. /*
  639.  *  0xhex
  640.  *  0octal
  641.  *  1-9decimal
  642.  */
  643.  
  644. int
  645. ParseInt(buf, i, max, pv)
  646. char *buf;
  647. long i;
  648. long max;
  649. long *pv;
  650. {
  651.     char c;
  652.     long v = 0;
  653.  
  654.     if (i < max && buf[i] == '0') {
  655.     ++i;
  656.     if (i < max && (buf[i] == 'x' || buf[i] == 'X')) {   /*  hex */
  657.         short n;
  658.         ++i;
  659.         while (i < max && (n = HexDig(buf[i])) >= 0) {
  660.         v = (v << 4) + n;
  661.         ++i;
  662.         }
  663.     } else {                         /*  oct */
  664.         short n;
  665.         while (i < max && (n = OctDig(buf[i])) >= 0) {
  666.         v = (v << 3) + n;
  667.         ++i;
  668.         }
  669.     }
  670.     } else {
  671.     while (i < max && (c = buf[i]) >= '0' && c <= '9') { /*  dec */
  672.         v = v * 10 + c - '0';
  673.         ++i;
  674.     }
  675.     }
  676.     while ((c = buf[i]) == 'L' || c == 'l' || c == 'U' || c == 'u')
  677.     ++i;
  678.     *pv = v;
  679.     return(i);
  680. }
  681.  
  682. int
  683. HexDig(char c)
  684. {
  685.     if (c >= '0' && c <= '9')
  686.     return (c - '0');
  687.     if (c >= 'a' && c <= 'f')
  688.     c = c + ('A' - 'a');
  689.     if (c >= 'A' && c <= 'F')
  690.     return (c + (10 - 'A'));
  691.     return(-1);
  692. }
  693.  
  694. int
  695. OctDig(char c)
  696. {
  697.     if (c >= '0' && c <= '7')
  698.     return (c - '0');
  699.     return(-1);
  700. }
  701.  
  702.